/*
 * Copyright 2009-2015 by WWW.KNET.CN  All rights reserved.
 */

package cn.knet.sp.ncrm.common.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

import cn.knet.sp.ncrm.common.service.ExportSynService;

/**
 * User: zhangbin CreateDate: 2015/5/8 10:30
 *
 * @author zhangbin
 * @version 2015 /05/08 15:39:32
 */
@Aspect
@Component
public class ExportLockAspect {

	/**
	 * 日志记录
	 */
	private static final Logger logger = LoggerFactory.getLogger(ExportLockAspect.class);

	/**
	 * 存储锁 释放机制
	 */
	private Map<String, ReentrantLock> lockers = new HashMap<String, ReentrantLock>();
	/**
	 * 可以存储内容 但是这个ID需要程序中自己控制
	 */
	private Map<String, Object> lockersRequest = new HashMap<String, Object>();

	/**
	 * 仅做初始化打印
	 */
	ExportLockAspect() { //为何不用public? 为了防止重复创建
		logger.info("export locker has init");
		//System.err.println("export locker has init");
	}

	@Around("@annotation(excelLock)&& within(cn.knet.sp.ncrm.modules..*.*)")
	public Object aroundExport(ProceedingJoinPoint joinPoint, ExportExcelLock excelLock) {
		Object result = null;
		//进入方法之前首先加上锁
		logger.info("export with aop locker");
		logger.info("joinPoint kind={},target={}", joinPoint.getKind(), joinPoint.getTarget());
		ReentrantLock reentrantLock = lockers.get(excelLock.lockerId());
		if (reentrantLock == null) {
			reentrantLock = new ReentrantLock();
			lockers.put(excelLock.lockerId(), reentrantLock);
		}
		if (excelLock.hasTry()) {
			if (reentrantLock.tryLock()) {
				try {
					result = joinPoint.proceed();
				} catch (Throwable e) {
					logger.warn("joinPoint proceed Exception", e);
				} finally {
					reentrantLock.unlock();
					this.lockersRequest.remove(excelLock.lockerId()); //删除对象
				}
			} else {
				return errorWithMessage(excelLock.lockMessage());
			}
		} else {
			reentrantLock.lock();
			try {
				result = joinPoint.proceed();
			} catch (Throwable e) {
				logger.warn("joinPoint proceed Exception", e);
			} finally {
				reentrantLock.unlock();
			}
		}
		return result;
	}

	/**
	 * 返回的就是一个String 吧message的参数 给加码
	 *
	 * @param message the message
	 * @return the string
	 * @author zhangbin
	 * @date 2015 /05/14 15:10:54
	 */
	private String errorWithMessage(String message) {
		try {
			message = URLEncoder.encode(message, "UTF-8");
			message = "?message=" + message;
		} catch (UnsupportedEncodingException e) {
			message = "";
			logger.warn("转码发生异常 message={}", message, e);
		}
		return ExportSynService.FOWAED_ERROR + message;
	}

	/**
	 * 如果 isLocked 是 false 说明没有锁定 可以加锁 因此返回true
	 *
	 * @param lockerId the locker id
	 * @return the boolean
	 * @author zhangbin
	 * @date 2015 /05/13 17:39:43
	 */
	public boolean canBeenLocked(String lockerId) {
		ReentrantLock locker = lockers.get(lockerId);
		if (locker == null) {
			return true; //若id不存在 则认为可以锁定
		}
		return !locker.isLocked();
	}

	public void putStateObject(String id, Object o) {
		this.lockersRequest.put(id,o);
	}

	public Object getStateObject(String id){
		return this.lockersRequest.get(id);
	}
}
